import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter_color_plugin/flutter_color_plugin.dart';
import 'package:detect/utils/global.dart';

class Chart extends StatefulWidget {
  final List<List<int>> data;
  final int splitX, splitY;
  final int max, min;

  const Chart({super.key, required this.data, this.splitX = 10, this.splitY = 5, this.min = 0, this.max = 100});

  @override
  State<Chart> createState() => _ChartState();
}

class _ChartState extends State<Chart> {
  @override
  Widget build(BuildContext context) => ClipRect(child: CustomPaint(painter: _Painter(widget.data, widget.splitX, widget.splitY, widget.min, widget.max)));
}

class _Painter extends CustomPainter {
  final List<List<int>> data;
  final int max, min;
  late int splitNumber, maxSplitNumber, minSplitNumber;
  int splitX, splitY;
  Rect _drawLineRect = Rect.zero;

  _Painter(this.data, this.splitX, this.splitY, this.min, this.max) {
    splitNumber = splitY;
    // max = data.isNotEmpty ? Global.maxs<int>(data.map((e) => Global.maxs(e) ?? 0).toList()) ?? 0 : 0;
    // min = data.isNotEmpty ? Global.mins<int>(data.map((e) => Global.mins(e) ?? 0).toList()) ?? 0 : 0;
    minSplitNumber = min;
    maxSplitNumber = (max - min).abs();
    int mod = maxSplitNumber % splitNumber;
    maxSplitNumber = mod > 0 ? splitNumber - mod + maxSplitNumber : maxSplitNumber;
    int realSplitY = maxSplitNumber ~/ splitNumber;
    splitY = realSplitY < splitY ? realSplitY : splitY;
    splitNumber = maxSplitNumber ~/ splitY;
  }

  // _Painter(this.data, this.splitX, this.splitY) {
  //   max = data.isNotEmpty ? Global.maxs<int>(data.last) ?? 0 : 0;
  //   min = data.isNotEmpty ? Global.mins<int>(data.last) ?? 0 : 0;
  //   int defaultSplitNumber = 5, realSplitY = ((max - min).abs() / defaultSplitNumber).ceil();
  //   if (realSplitY > splitY) {
  //     splitNumber = (realSplitY / splitY).ceil() * defaultSplitNumber;
  //   } else {
  //     splitNumber = defaultSplitNumber;
  //   }
  //   int splitYNumberTotal = splitY * splitNumber, maxSplitNumber = splitYNumberTotal;
  //   while (maxSplitNumber - max > defaultSplitNumber) {
  //     maxSplitNumber -= defaultSplitNumber;
  //   }
  //   this.maxSplitNumber = maxSplitNumber;
  //   minSplitNumber = maxSplitNumber - splitYNumberTotal;
  // }

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint();
    paint.isAntiAlias = true;
    paint.strokeCap = StrokeCap.round;
    paint.strokeJoin = StrokeJoin.round;
    paint.style = PaintingStyle.stroke;
    paint.strokeWidth = 1;
    double width = size.width, height = size.height / 2;
    if (data.isNotEmpty && data.last.isNotEmpty) {
      _drawLine(canvas, paint, width, height);
      _drawWaterfall(canvas, paint, width - _drawLineRect.left, height);
    }
  }

  @override
  bool shouldRepaint(covariant _Painter old) => true;

  Offset _valueToPoint(num value, [int index = 0]) => Offset(_drawLineRect.width / (data.isNotEmpty ? data.last.length : 0) * index + _drawLineRect.left, _drawLineRect.height / (maxSplitNumber - minSplitNumber) * (maxSplitNumber - value) + _drawLineRect.top);

  TextPainter _createLabel(int value) => TextPainter(
        text: TextSpan(text: value.toString(), style: TextStyle(fontSize: Global.ds(14), color: ColorUtil.color("#D4D4D4"))),
        textDirection: TextDirection.ltr,
        textAlign: TextAlign.right,
        maxLines: 1,
      );

  void _drawLine(Canvas canvas, Paint paint, double width, double height) {
    TextPainter textPainterMin = _createLabel(minSplitNumber)..layout(maxWidth: width), textPainterMax = _createLabel(maxSplitNumber)..layout(maxWidth: width);
    Size axisYLabelSize = Size(math.max(textPainterMin.width, textPainterMax.width), math.max(textPainterMin.height, textPainterMax.height));
    double axisYLabelMargin = Global.ds(5);
    double leftPadding = axisYLabelSize.width + axisYLabelMargin, verticalPadding = axisYLabelSize.height / 2, stepX = (width - leftPadding) / splitX, stepY = (height - verticalPadding * 2) / splitY;
    canvas.save();
    canvas.translate(0, verticalPadding);
    _drawLineRect = Rect.fromLTWH(leftPadding, 0, width - leftPadding, height - verticalPadding * 2);
    //x轴线条
    for (int x = 0; x <= splitX; x++) {
      paint.color = Colors.white.withOpacity(.15);
      canvas.drawLine(_drawLineRect.topLeft.translate(x * stepX, 0), _drawLineRect.bottomLeft.translate(x * stepX, 0), paint);
    }
    //y轴线条
    for (int y = 0; y <= splitY; y++) {
      int value = maxSplitNumber - (splitY - y) * splitNumber;
      TextPainter label = _createLabel(value)..layout(maxWidth: width);
      label.paint(canvas, _valueToPoint(value).translate(-label.width - axisYLabelMargin, -_drawLineRect.top - label.height / 2));
      paint.color = Colors.white.withOpacity(.15);
      canvas.drawLine(_drawLineRect.topLeft.translate(0, y * stepY), _drawLineRect.topRight.translate(0, y * stepY), paint);
    }
    Path linePath = Path(), areaPath = Path();
    List<Offset> points = [];
    points.add(_drawLineRect.bottomLeft);
    for (int i = 0; i < data.last.length; i++) {
      Offset point = _valueToPoint(data.last[i], i);
      if (i > 0) {
        linePath.lineTo(point.dx, point.dy);
      } else {
        linePath.moveTo(point.dx, point.dy);
      }
      points.add(point);
    }
    points.add(_drawLineRect.bottomRight);
    areaPath.addPolygon(points, true);
    paint.color = ColorUtil.color("#60D8E1");
    canvas.drawPath(linePath, paint);
    paint.style = PaintingStyle.fill;
    paint.color = ColorUtil.color("#60D8E1").withOpacity(.15);
    canvas.drawPath(areaPath, paint);
    canvas.restore();
  }

  void _drawWaterfall(Canvas canvas, Paint paint, double width, double height) {
    //4279489767  4279269873
    double drawHeight = 0;
    int minColorValue = 4279489767, maxColorValue = 4279269873;
    paint.color = Color(minColorValue);
    canvas.drawRect(Rect.fromLTWH(_drawLineRect.left, height, width, height), paint);
    List<List<int>> dataClone = [...data];
    for (int i = dataClone.length - 1; i >= 0; i--) {
      double blockSize = width / dataClone[i].length;
      int max = Global.maxs<int>(dataClone[i]) ?? 0, min = Global.mins<int>(dataClone[i]) ?? 0;
      for (int n = 0; n < dataClone[i].length; n++) {
        double ratio = (dataClone[i][n] - min) / (max - min);
        // paint.color = paint.color.withOpacity(ratio);
        paint.color = Color(((maxColorValue - minColorValue) * ratio).toInt() + minColorValue);
        canvas.drawRect(Rect.fromLTWH(n * blockSize + _drawLineRect.left, height + drawHeight, blockSize, blockSize), paint);
      }
      if (drawHeight + blockSize > height) {
        data.removeRange(0, i);
        break;
      } else {
        drawHeight += blockSize;
      }
    }
  }
}
